package com.dl.controller;

import com.alibaba.fastjson.JSONObject;
import com.dl.config.jwt.BaseResponse;
import com.dl.config.jwt.JwtTokenManager;
import com.dl.pojo.User;
import com.dl.service.UserService;
import com.dl.utils.ConstantField;
import com.dl.utils.ShiroUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

/**
 * @author DL
 * @create 2021-03-23 14:26
 * getServletPath():获取能够与“url-pattern”中匹配的路径，注意是完全匹配的部分，*的部分不包括。
 * getPathInfo():与getServletPath()获取的路径互补，能够得到的是“url-pattern”中*d的路径部分
 * getContextPath():获取项目的根路径
 * getRequestURI:获取根路径到地址结尾
 * getRequestURL:获取请求的地址链接（浏览器中输入的地址）
 * getServletContext().getRealPath("/"):获取“/”在机器中的实际地址
 * getScheme():获取的是使用的协议(http 或https)
 * getProtocol():获取的是协议的名称(HTTP/1.11)
 * getServerName():获取的是域名(xxx.com)
 * getLocalName:获取到的是IP
 */
@Controller
@RequestMapping("/test")
@Log4j2
public class test {

    @Resource
    private JwtTokenManager jwtTokenManager;

    @PostMapping("/login")
    @ResponseBody
    public BaseResponse login(HttpSession session, RedirectAttributes redirectAttributes,
                              String username, String password, String captcha, @RequestParam(defaultValue = "0") String rememberMe){

        String sessionCaptcha = (String) session.getAttribute("sessionCaptcha");

        //将字符串与指定的对象比较，不考虑大小写
        if ("admin".equals(username) || sessionCaptcha.equalsIgnoreCase(captcha)){
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
            //封装登录用户数据
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            try {
                if (rememberMe.equals("1")){//判断是否开启记住我功能
                    System.out.println("rememberME");
                    token.setRememberMe(true);
                }
                //交由shiro执行登录，如果没有抛出异常则成功
                subject.login(token);
                System.out.println("======================login之后=====================");
                //登录成功颁发令牌
                Session subjectSession = subject.getSession();
                User user = (User) subjectSession.getAttribute(ConstantField.LOGIN_INFO);
                String sessionId = ShiroUtils.getSessionId();
                Map<String,Object> claims = new HashMap<>();
                claims.put("user", JSONObject.toJSONString(user));
                String jwtToken = jwtTokenManager.issueToken("system", subjectSession.getTimeout(), sessionId, claims);

                return new BaseResponse(BaseResponse.LOGIN_SUCCESS_CODE, BaseResponse.LOGIN_SUCCESS_MESSAGE, jwtToken);
            }catch (LockedAccountException e){
                log.info("账号锁定:{}", username);
                return new BaseResponse(BaseResponse.LOGIN_FAILURE_CODE,BaseResponse.LOGIN_FAILURE_MESSAGE);
            }catch (UnknownAccountException e){
                log.info("登录异常:{}", username);
                redirectAttributes.addFlashAttribute("msg","用户名错误");
                return null;
            }catch (IncorrectCredentialsException e){
                log.info("密码错误:{}", username);
                redirectAttributes.addFlashAttribute("msg","密码错误");
                return null;
            }catch (ExcessiveAttemptsException e){
                log.info("错误次数过多:{}", username);
                redirectAttributes.addFlashAttribute("msg",e.getMessage());
                return null;
            }
        }else {
            redirectAttributes.addFlashAttribute("msg","验证码错误");
            return null;
        }
    }



    @Resource
    UserService userService;

    @GetMapping("/")
    public String upload(){
        return "test/vueTest";
    }

    @GetMapping("/el")
    public String el(){
        return "commons/element-ui/综合";
    }

    @GetMapping("/vuel1")
    public String vuel1(){
        return "test/vue-elTest";
    }

    @GetMapping("/vuel2")
    public String vuel2(){
        return "test/vue-elTest2";
    }

    @RequestMapping("/os")
    public void os(){
        System.out.println("System.getProperty(\"os.name\") = " + System.getProperty("os.name"));
        System.out.println("System.getProperty(\"user.name\") = " + System.getProperty("user.name"));
        System.out.println("System.getProperty(\"user.dir\") = " + System.getProperty("user.dir"));
        System.out.println("System.getProperty(\"user.home\") = " + System.getProperty("user.home"));
        System.out.println("System.getProperty(\"java.class.path\") = " + System.getProperty("java.class.path"));
        System.out.println("System.getProperty(\"java.home\") = " + System.getProperty("java.home"));
        System.out.println("System.getProperty(\"security.destroy\") = " + System.getProperty("security.destroy"));
        System.out.println("System.getProperty(\"os.version\") = " + System.getProperty("os.version"));
    }

    @RequestMapping("/path")
    public void path() throws FileNotFoundException {
        System.out.println("System.getProperty(\"user.dir\") = " + System.getProperty("user.dir"));

        // webapp目录
        String classpath = this.getClass().getResource("/").getPath().replaceFirst("/", "");
        System.out.println("classpath = " + classpath);

        //获取classes目录绝对路径
        String path1 = ClassUtils.getDefaultClassLoader().getResource("").getPath();
        String path2 = ResourceUtils.getURL("classpath:").getPath();
        System.out.println("path1 = " + path1);
        System.out.println("path2 = " + path2);

        //如果上传目录为/static/images/upload/，则可以如下获取：

        File file = new File("/static/img/avatar.svg");
        //取得相对路径
        System.out.println("Path: " + file.getPath());
        //取得绝对路径
        System.out.println("getAbsolutePath: " + file.getAbsolutePath());
        //在开发测试模式时，得到的地址为：{项目跟目录}/target/static/images/upload/
        //在打包成jar正式发布时，得到的地址为：{发布jar包目录}/static/images/upload/

    }



    @RequestMapping("/test")
    public void test(HttpServletRequest request) throws IOException {

        // File.separator 系统分隔符
        System.out.println("request.getServletContext().getRealPath(\"/upload\") = " +
                request.getServletContext().getRealPath(File.separator + "upload"));

        System.out.println("request.getServletContext().getRealPath(\"/\") = " +
                request.getServletContext().getRealPath("/"));

        System.out.println("request.getServletContext().getResource(File.separator).getPath() = " +
                request.getServletContext().getResource(File.separator).getPath());

        System.out.println("this.getClass().getClassLoader().getResource(File.separator).getPath() = " +
                this.getClass().getClassLoader().getResource(File.separator).getPath());

        String path = this.getClass().getClassLoader().getResource(File.separator).getPath();

        //对uri进行转码
        String decode = URLDecoder.decode(path, "utf-8");
        System.out.println("decode = " + decode);

    }


    @Resource
    private PlatformTransactionManager transactionManager;

    @RequestMapping("save")
    @ResponseBody
    public String save(Object a, Object b){
        DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
        defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);

        try {
            //service.saveObjectA(a);
            //service.saveObjectB(b);
            transactionManager.commit(status);
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(status);
            return "save failed";
        }
        return "save successful";
    }
}
